home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 21 / Cream of the Crop 21 (Terry Blount) (October 1996).iso / os2 / vsoup11.zip / socket.cc < prev    next >
C/C++ Source or Header  |  1996-09-02  |  7KB  |  319 lines

  1. //  $Id: socket.cc 1.13 1996/09/02 13:30:23 hardy Exp $
  2. //
  3. //  This progam/module was written by Hardy Griech based on ideas and
  4. //  pieces of code from Chin Huang (cthuang@io.org).  Bug reports should
  5. //  be submitted to rgriech@ibm.net.
  6. //
  7. //  This file is part of soup++ for OS/2.  Soup++ including this file
  8. //  is freeware.  There is no warranty of any kind implied.  The terms
  9. //  of the GNU Gernal Public Licence are valid for this piece of software.
  10. //
  11. //  simple socket class
  12. //
  13. //  attention:
  14. //  ----------
  15. //  TSocket::open requires semaphor support for multithreaded environment.
  16. //  For OS/2 it's implemented, but not for any other os!
  17. //
  18.  
  19.  
  20. #include <sys/types.h>
  21. #include <sys/socket.h>
  22. #include <ctype.h>
  23. #include <stdarg.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <netdb.h>
  28. #include <arpa/inet.h>
  29. #include <netinet/in.h>
  30.  
  31. #include "mts.hh"
  32. #include "socket.hh"
  33. #include "sema.hh"
  34.  
  35.  
  36.  
  37. TSocket::TSocket( void )
  38. {
  39.     State = init;
  40. }   // TSocket::TSocket
  41.  
  42.  
  43.  
  44. TSocket::~TSocket()
  45. {
  46.     if (State == connected)
  47.     close();
  48. }   // TSocket::~TSocket
  49.  
  50.  
  51.  
  52. void TSocket::close( void )
  53. {
  54. #ifdef TRACE_ALL
  55.     printfT( "TSocket::close()\n" );
  56. #endif
  57.  
  58.     while (State == connecting)
  59.     _sleep2( 100 );
  60.     
  61.     if (State == connected) {
  62. #ifdef DEBUG_ALL
  63.     printfT( "closing %s:%s/%s\n", ipAdr,service,protocol );
  64. #endif
  65.     shutdown( sock,2 );
  66.     
  67. ////    delete ipAdr;    ipAdr = NULL;
  68. ////    delete service;  service = NULL;
  69. ////    delete protocol; protocol = NULL;
  70. ////    delete Buffer;   Buffer = NULL;
  71.     }
  72.     State = closed;
  73. }   // TSocket::close
  74.  
  75.  
  76.  
  77. int TSocket::open( const char *ipAdr, const char *service, const char *protocol,
  78.            int buffSize )
  79. //
  80. //  Socket öffnen:  Parameter sind wohl halbwegs klar...
  81. //  - Es muß beim Return aufgepaßt werden, daß State != connecting gesetzt wird - sonst
  82. //    wartet der close() u.U. endlos...
  83. //  - Open() muß im MT-Fall mit Semaphoren abgesichert werden, da diverse Socket-Fkts
  84. //    Zeiger auf statische Struct zurückgeben!
  85. //  - der einfachheithalber wird im Fehlerfall mit einem GOTO ans Ende gesprungen.  Dort
  86. //    wird dann u.a. das Semaphor freigegeben
  87. //  
  88. //  Return: >=0 -> ok
  89. //          < 0 -> failed (im Moment keine weiteren Angaben)
  90. //
  91. {
  92.     int Result;
  93.     int port;
  94.     unsigned long inaddr;
  95.     struct sockaddr_in ad;
  96.     static TSemaphor OpenSema;
  97.  
  98. #ifdef TRACE_ALL
  99.     printfT( "TSocket::open(%s,%s,%s,%d)\n",ipAdr,service,protocol,buffSize );
  100. #endif
  101.  
  102.     if (State != closed  &&  State != init)
  103.     close();
  104.  
  105.     State = connecting;
  106.     Result = -1;
  107.  
  108.     OpenSema.Request();
  109.  
  110. #ifdef DEBUG_ALL
  111.     printfT( "opening %s:%s/%s\n", ipAdr,service,protocol );
  112. #endif
  113.  
  114.     memset(&ad, 0, sizeof(ad));
  115.  
  116.     //
  117.     //  Ist die Adresse als 32bit-IP-Adresse oder als Name angegeben ?
  118.     //
  119.     inaddr = inet_addr(ipAdr);
  120.     if (inaddr != INADDR_NONE) {
  121.     ad.sin_family = AF_INET;
  122.     ad.sin_addr.s_addr = inaddr;
  123.     }
  124.     else {
  125.     struct hostent *host;
  126.  
  127. #ifdef DEBUG_ALL
  128.     printfT( "TSocket::open:  before gethostbyname\n" );
  129. #endif
  130.     host = gethostbyname( ipAdr );
  131.     if (host == NULL)
  132.         goto OpenEnd;
  133.     ad.sin_family = host->h_addrtype;
  134.     memcpy(&ad.sin_addr, host->h_addr, host->h_length);
  135. #ifdef DEBUG_ALL
  136.     printfT( "TSocket::open:  behind gethostbyname\n" );
  137. #endif
  138.     }
  139.  
  140.     //
  141.     //  Service auseinanderfieseln
  142.     //
  143.     if (isdigit(service[0]))
  144.     port = htons( atoi(service) );
  145.     else {
  146.     struct servent *serv;
  147.  
  148.     serv = getservbyname (service,protocol);
  149.     if (serv == NULL)
  150.         goto OpenEnd;
  151.     port = serv->s_port;
  152.     }
  153.     ad.sin_port = port;
  154.  
  155.     //
  156.     //  Verbindung aufbauen
  157.     //
  158.     sock = socket( AF_INET, SOCK_STREAM, 0 );
  159.     if (sock < 0)
  160.     goto OpenEnd;
  161.     if (connect(sock,(struct sockaddr *)&ad,sizeof(ad)) < 0)
  162.     goto OpenEnd;
  163.     Result = sock;
  164.  
  165.     //
  166.     //  setup buffer
  167.     //
  168.     Buffer = new unsigned char [buffSize+10];   ////
  169.     TSocket::BuffSize = buffSize;
  170.     BuffNdx = BuffEnd = 0;
  171.  
  172.     //
  173.     //  store ip&protocol
  174.     //
  175.     TSocket::ipAdr = xstrdup(ipAdr);
  176.     TSocket::service = xstrdup(service);
  177.     TSocket::protocol = xstrdup(protocol);
  178.  
  179. OpenEnd:
  180.     if (Result >= 0) {
  181. #ifdef DEBUG_ALL
  182.     printfT( "socket opened successfully %s,%s/%s\n",
  183.          TSocket::ipAdr,TSocket::service,TSocket::protocol );
  184. #endif
  185.     State = connected;
  186.     }
  187.     else
  188.     State = closed;
  189.     
  190.     OpenSema.Release();
  191.  
  192.     return Result;
  193. }   // TSocket::open
  194.  
  195.  
  196.  
  197. int TSocket::send( void *src, int len )
  198. {
  199.     int n;
  200.     char *buf = (char *)src;
  201.  
  202.     while (len) {
  203.         n = ::send( sock, buf, len, 0 );
  204.         if (n <= 0)
  205.             return -1;
  206.         len -= n;
  207.         buf += n;
  208.     }
  209.     return 0;
  210. }   // TSocket::send
  211.  
  212.  
  213.  
  214. int TSocket::printf( const char *fmt, ... )
  215. {
  216.     va_list ap;
  217.     char buf[BUFSIZ];
  218.     int res;
  219.  
  220.     res = -1;
  221.     if (State == connected) {
  222.     va_start( ap, fmt );
  223.     vsprintfT( buf, fmt, ap );
  224.     va_end( ap );
  225.     res = send( buf, strlen(buf) );
  226.     }
  227.     return res;
  228. }   // TSocket::printf
  229.  
  230.  
  231.  
  232. int TSocket::puts( const char *s )
  233. {
  234.     return printf( "%s\n",s ) > 0;
  235. }   // TSocket::puts
  236.  
  237.  
  238.  
  239. int TSocket::nextchar( void )
  240. {
  241.     if (State != connected  ||  BuffEnd < 0)
  242.     return -1;
  243.     
  244.     if (BuffNdx >= BuffEnd) {
  245.     BuffEnd = recv( sock, Buffer, BuffSize, 0 );
  246.     if (BuffEnd <= 0) {
  247. #ifndef NDEBUG
  248.         printfT( "TSocket::nextchar() error: %d\n",errno );
  249. #endif
  250.         BuffEnd = -1;
  251.         return -1;
  252.     }
  253.     BuffNdx = 0;
  254.     }
  255.     return Buffer[BuffNdx++];
  256. }   // TSocket::nextchar
  257.  
  258.  
  259.  
  260. char *TSocket::gets( char *buff, int bufflen )
  261. //
  262. //  gets from socket ('\n' is not contained in return buff)
  263. //  on EOF NULL is returned, otherwise buff
  264. //
  265. {
  266.     char *p;     // Zeiger auf gelesene Zeichen
  267.     int  n;      // Anzahl der gelesenen Zeichen
  268.     int  c;      // gelesenes Zeichen
  269.  
  270.     if (bufflen <= 1) {             // buff muß min. 2 Zeichen lang sein!
  271. #ifdef DEBUG
  272.     printfT( "TSocket::gets():  ill bufflen %d\n",bufflen );
  273. #endif
  274.     return NULL;
  275.     }
  276.  
  277.     p = buff;
  278.     n = 0;
  279.     for (;;) {
  280.     if (n >= bufflen-2) {       // if Buffer exhausted, read til '\n'
  281.         do
  282.         c = nextchar();
  283.         while (c != '\n'  &&  c != -1);
  284.         break;
  285.     }
  286.  
  287.     c = nextchar();
  288.     if (c == -1) {              // EOF!
  289.         if (n == 0) {
  290.         *p = '\0';
  291. #ifdef DEBUG
  292.         strcpy( buff,"!!EOF!!" );
  293. #endif
  294.         return( NULL );
  295.         }
  296.         else
  297.         break;
  298.     }
  299.     else if (c == '\r')         // skip '\r'
  300.         continue;
  301. #if 0   // RFC977 caught by reality???
  302.     else if (c >= 0x80) {       // skip chars >= 0x80 (RFC977!)
  303. #ifndef NDEBUG
  304.         printfT( "TSocket::gets(): ill char 0x%02x\n", c);
  305. #endif
  306.         continue;
  307.     }
  308. #endif
  309.     else if (c == '\n')         // Zeile fertig !
  310.         break;
  311.     else {
  312.         *(p++) = c;
  313.         ++n;
  314.     }
  315.     }
  316.     *p = '\0';
  317.     return buff;
  318. }   // TSocket::gets
  319.